package com.iwhalecloud.bss.kite.cucc.web.service.accept.handler.module;

import com.iwhalecloud.bss.kite.client.dto.accept.in.AcceptRequestInDTO;
import com.iwhalecloud.bss.kite.client.dto.dirty.DirtyProdInstDTO;
import com.iwhalecloud.bss.kite.client.vo.scene.ModuleVO;
import com.iwhalecloud.bss.kite.client.vo.scene.ProdRoleModuleVO;
import com.iwhalecloud.bss.kite.client.vo.scene.ProductModuleVO;
import com.iwhalecloud.bss.kite.client.vo.scene.SceneVO;
import com.iwhalecloud.bss.kite.client.vo.spec.RoleButtonVO;
import com.iwhalecloud.bss.kite.common.constant.KeyConsts;
import com.iwhalecloud.bss.kite.common.util.KiteStringUtils;
import com.iwhalecloud.bss.kite.cucc.client.vo.scene.SceneNewOfferSeneVO;
import com.iwhalecloud.bss.kite.dataservice.cache.AdditionalExtProdCache;
import com.iwhalecloud.bss.kite.dataservice.cache.OfferObjRelRoleCache;
import com.iwhalecloud.bss.kite.dataservice.entity.OfferObjRelRole;
import com.iwhalecloud.bss.kite.manager.enums.ActionType;
import com.iwhalecloud.bss.kite.manager.enums.InstType;
import com.iwhalecloud.bss.kite.manager.inst.KiteProdInst;
import com.iwhalecloud.bss.kite.manager.inst.graph.impl.RelEdge;
import com.iwhalecloud.bss.kite.web.service.accept.bo.AcceptContext;
import com.iwhalecloud.bss.kite.web.service.accept.bo.DirtyDataWrapper;
import com.iwhalecloud.bss.kite.web.service.accept.bo.SceneModule;
import com.iwhalecloud.bss.kite.web.service.accept.constant.TemplateConsts;
import com.iwhalecloud.bss.kite.web.service.accept.handler.module.AbstractModuleHandler;
import com.iwhalecloud.bss.kite.web.service.accept.handler.module.ProductAttrModuleHandler;
import com.iwhalecloud.bss.kite.web.service.accept.service.SceneModuleCache;
import com.iwhalecloud.bss.kite.web.service.scene.SceneService;
import com.ztesoft.bss.order.base.unicode.UnicodeRole;
import com.ztesoft.bss.svcability.util.ListUtil;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <Description> 产品角色处理 <br>
 *
 * @author zhu.zixin<br>
 * @version 1.0<br>
 * @taskId <br>
 */
@Service
@Primary
public class LocalProductRoleModuleHandler extends AbstractModuleHandler {

    @Override
    public List<? extends ModuleVO> execute(AcceptContext context, SceneModule sceneModule) {
        return getScene(context, sceneModule);
    }

    @Override
    public List<? extends ModuleVO> previewSceneVo(AcceptContext context, SceneModule sceneModule) {
        return getScene(context, sceneModule);
    }

    private List<ProdRoleModuleVO> getScene(AcceptContext context, SceneModule sceneModule) {
        /**
         * 这里面只需直接返回，用于构建子组件的父对象
         */
        ProductModuleVO product = (ProductModuleVO) sceneModule.getParentModuleVO();
        sortProdRole(product.getProdRole());

        if (product.getRoleButton().size() > 0) {
            sortRoleButton(product.getRoleButton());
        }

        return product.getProdRole();
    }

    /**
     * 根据角色排序
     */
    private void sortProdRole(List<ProdRoleModuleVO> prodRoleInst) {
        prodRoleInst.sort((ProdRoleModuleVO o1, ProdRoleModuleVO o2) -> {
            int roleSortNum1 = 88;
            if (getSortMap().containsKey(o1.getProdRoleId())) {
                roleSortNum1 = getSortMap().get(o1.getProdRoleId());
            }
            int roleSortNum2 = 88;
            if (getSortMap().containsKey(o2.getProdRoleId())) {
                roleSortNum2 = getSortMap().get(o2.getProdRoleId());
            }

            if (roleSortNum1 == roleSortNum2) {
                //角色相同 根据状态排一下 A的排在后面
                String actionType1 = Optional.ofNullable(o1.getActionType()).orElse(KeyConsts.ACTION_TYPE_A);
                String actionType2 = Optional.ofNullable(o2.getActionType()).orElse(KeyConsts.ACTION_TYPE_A);
                if (actionType1.equals(actionType2)) {
                    boolean t =  Long.valueOf(o1.getProdInstId()) < Long.valueOf(o2.getProdInstId());
                    return t ? -1 : 1;
                }
                else if (KeyConsts.ACTION_TYPE_A.equals(actionType1)) {
                    roleSortNum1++;
                }
                else if (KeyConsts.ACTION_TYPE_A.equals(actionType2)) {
                    roleSortNum2++;
                }
            }

            return Integer.compare(roleSortNum1, roleSortNum2);
        });
    }

    /**
     * 根据角色排序
     */
    protected void sortRoleButton(List<RoleButtonVO> roleButtonList) {
        roleButtonList.sort((o1, o2) -> {
            int roleSortNum1 = 100;
            if (getSortMap().containsKey(o1.getProdRoleId())) {
                roleSortNum1 = getSortMap().get(o1.getProdRoleId());
            }
            int roleSortNum2 = 100;
            if (getSortMap().containsKey(o2.getProdRoleId())) {
                roleSortNum2 = getSortMap().get(o2.getProdRoleId());
            }
            return Integer.compare(roleSortNum1, roleSortNum2);
        });
    }


    private Map<String, Integer> getSortMap() {
        // 角色排序 主卡 固话 宽带 主ITV
        Map<String, Integer> sortMap = new HashMap<>();
        sortMap.put(UnicodeRole.ROLE_100000, 1);
        sortMap.put(UnicodeRole.ROLE_100009, 2);
        sortMap.put(UnicodeRole.ROLE_100008, 3);
        sortMap.put(UnicodeRole.ROLE_100010, 5);
        return sortMap;
    }

    @Override
    public List<? extends ModuleVO> refresh(AcceptContext context, SceneModule sceneModule, DirtyDataWrapper dirtyDataWrapper) {
        List<ProdRoleModuleVO> addProdRoleModuleVOs = refreshForAdd(context, sceneModule, dirtyDataWrapper);
        List<ProdRoleModuleVO> delProdRoleModuleVOs = refreshForRemove(sceneModule, dirtyDataWrapper);
        List<ProdRoleModuleVO> prodRoles = Optional.ofNullable((ProductModuleVO) sceneModule.getParentModuleVO())
            .map(ProductModuleVO::getProdRole).orElse(Collections.emptyList());

        List<ProdRoleModuleVO> newProdRoles = new ArrayList<ProdRoleModuleVO>();
        if (!ListUtil.isEmpty(addProdRoleModuleVOs) || !ListUtil.isEmpty(delProdRoleModuleVOs)) {
            for (ProdRoleModuleVO tmpProdRoleModuleVo : prodRoles) {
                String prodInstId = tmpProdRoleModuleVo.getProdInstId();
                boolean flag = delProdRoleModuleVOs.removeIf(p -> KiteStringUtils.isEqual(prodInstId, p.getProdInstId()));

                if (flag) {
                    if (!ListUtil.isEmpty(addProdRoleModuleVOs)) {
                        newProdRoles.add(addProdRoleModuleVOs.remove(0));
                    }
                }
                else {
                    newProdRoles.add(tmpProdRoleModuleVo);
                }
            }

            // 添加本次新增产品角色模块
            newProdRoles.addAll(addProdRoleModuleVOs);

            // 删除本次新增产品角色模块
            newProdRoles.removeIf(t -> delProdRoleModuleVOs.stream().anyMatch(p -> KiteStringUtils.isEqual(p.getProdInstId(), t.getProdInstId())));

            sortProdRole(newProdRoles);
            ProductModuleVO product = (ProductModuleVO) sceneModule.getParentModuleVO();
            product.setProdRole(newProdRoles);
            if (product.getRoleButton().size() > 0) {
                sortRoleButton(product.getRoleButton());
            }
        }
        return ((ProductModuleVO) sceneModule.getParentModuleVO()).getProdRole();
    }

    protected List<ProdRoleModuleVO> refreshForRemove(SceneModule sceneModule, DirtyDataWrapper dirtyDataWrapper) {
        List<ProdRoleModuleVO> delProdRoleModuleVOs = new ArrayList<ProdRoleModuleVO>();
        ProductModuleVO productModuleVO = (ProductModuleVO) sceneModule.getParentModuleVO();
        if (null == productModuleVO) {
            return delProdRoleModuleVOs;
        }
        List<ProdRoleModuleVO> prodRoleModuleVOs = productModuleVO.getProdRole();

        List<DirtyProdInstDTO> dirtyProdInsts = new ArrayList<>();

        Set<String> prodIds = prodRoleModuleVOs.stream().map(ProdRoleModuleVO::getProdId).collect(Collectors.toSet());
        prodIds.addAll(productModuleVO.getRoleButton().stream().map(RoleButtonVO::getProdId).collect(Collectors.toSet()));

        prodIds.forEach(prodIdTemp -> dirtyProdInsts.addAll(dirtyDataWrapper.listDirtyProdInsts(prodIdTemp, ActionType.D)));
        prodIds.forEach(prodIdTemp -> dirtyProdInsts.addAll(dirtyDataWrapper.listDirtyProdInsts(prodIdTemp, ActionType.X)));

        if (CollectionUtils.isNotEmpty(prodRoleModuleVOs) && CollectionUtils.isNotEmpty(dirtyProdInsts)) {
            Set<String> delInstIds = dirtyProdInsts.stream().map(DirtyProdInstDTO::getInstId).collect(Collectors.toSet());
            delProdRoleModuleVOs = prodRoleModuleVOs.stream().filter(t  ->  delInstIds.contains(t.getProdInstId())).collect(Collectors.toList());
//            return prodRoleModuleVOs.removeIf(t -> delInstIds.contains(t.getProdInstId()));
        }
        return delProdRoleModuleVOs;
    }

    protected  List<ProdRoleModuleVO> refreshForAdd(AcceptContext context, SceneModule sceneModule, DirtyDataWrapper dirtyDataWrapper) {
        List<ProdRoleModuleVO> addProdRoleModuleVOs = new ArrayList<>();
        ProductModuleVO productModuleVO = (ProductModuleVO) sceneModule.getParentModuleVO();
        if (null == productModuleVO) {
            return addProdRoleModuleVOs;
        }
        List<ProdRoleModuleVO> prodRoleModuleVOs = productModuleVO.getProdRole();

        // 礼包ProductModuleVO的prod_id可能跟ProdRoleModuleVO的prod_id不一样
        List<DirtyProdInstDTO> dirtyProdInsts = new ArrayList<>();
        Set<String> prodIds = prodRoleModuleVOs.stream().map(ProdRoleModuleVO::getProdId).collect(Collectors.toSet());
        prodIds.addAll(productModuleVO.getRoleButton().stream().map(RoleButtonVO::getProdId).collect(Collectors.toSet()));

        prodIds.forEach(prodIdTemp -> dirtyProdInsts.addAll(getAddProdInsts(dirtyDataWrapper, prodIdTemp)));

        if (CollectionUtils.isNotEmpty(dirtyProdInsts)) {
            /**
             * 因为{@link ProductAttrModuleHandler#execute}对新装的特殊处理，
             * 这里不得不重新构造一个新请求，令其serviceOfferId为空
             */
            AcceptRequestInDTO request = new AcceptRequestInDTO();
            request.setCustId(context.getAcceptRequest().getCustId());
            request.setSceneInstId(context.getAcceptRequest().getSceneInstId());
            request.setSceneTemplateId(context.getAcceptRequest().getSceneTemplateId());
            request.setOfferId(context.getAcceptRequest().getOfferId());

            SceneVO sceneVO = context.getSceneVo();
            List<ProdRoleModuleVO> tempProdRoleModules = new ArrayList<>(prodRoleModuleVOs);
            if (sceneVO instanceof SceneNewOfferSeneVO) {
                //加装可选包的话 可能存在多个prodId相同的ProductModuleVO 因此都要排除一遍
                for (ProductModuleVO moduleVO : ((SceneNewOfferSeneVO) sceneVO).getSceneProductModuleVO().getProduct()) {
                    tempProdRoleModules.addAll(moduleVO.getProdRole());
                }
            }

            for (DirtyProdInstDTO dirtyProdInstDTO : dirtyProdInsts) {
                if (tempProdRoleModules.stream().noneMatch(
                    prodRoleModuleVO -> prodRoleModuleVO.getProdInstId().equals(dirtyProdInstDTO.getInstId()))) {
                    if (addProdRoleModuleVOs.stream()
                        .noneMatch(p -> p.getProdInstId().equals(dirtyProdInstDTO.getInstId()))) {
                        addProdRoleModuleVOs.add(genProdRoleModuleVO(request, sceneModule, dirtyProdInstDTO, dirtyDataWrapper));
                    }
                }
            }
        }
        return addProdRoleModuleVOs;
    }

    /**
     * 判断是否有加实例
     * 主要是选老号码只加了关系没有加实例 TODO 暂时处理方式 后面再优化
     * @return
     */
    private List<DirtyProdInstDTO> getAddProdInsts(DirtyDataWrapper dirtyDataWrapper, String prodId) {
        List<DirtyProdInstDTO> boundProdInsts = dirtyDataWrapper.getSideBoundProdInsts();
        if (CollectionUtils.isNotEmpty(boundProdInsts)) {
            boundProdInsts = boundProdInsts.stream().filter(t -> Objects.equals(prodId, t.getProdId())).collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(boundProdInsts)) {
                return boundProdInsts;
            }
        }
        List<DirtyProdInstDTO> dirtyProdInsts = dirtyDataWrapper.listDirtyProdInsts(prodId, ActionType.A);
        if (CollectionUtils.isNotEmpty(dirtyProdInsts)) {
            return dirtyProdInsts;
        }
        int i = dirtyDataWrapper.listDirtyProdInsts(prodId, ActionType.D).size();
        if (i == 1) {
            List<RelEdge> addRel = dirtyDataWrapper.getKiteTransactionDTO().getAddRelEdges().stream()
                .filter(relEdge -> relEdge.getTargetInstType() == InstType.PROD_INST).collect(Collectors.toList());
            if (addRel.size() > 0) {
                KiteProdInst kiteProdInst = dirtyDataWrapper.getKiteTransactionDTO().getInst(InstType.PROD_INST, addRel.get(0).getTargetInstId());
                if (kiteProdInst != null && StringUtils.equals(kiteProdInst.getSpecId(), prodId)) {
                    DirtyProdInstDTO dirtyProdInstDTO = new DirtyProdInstDTO();
                    dirtyProdInstDTO.setRoleId(kiteProdInst.getRoleId());
                    dirtyProdInstDTO.setInstId(kiteProdInst.getProdInstId());
                    dirtyProdInstDTO.setSpecId(kiteProdInst.getSpecId());
                    dirtyProdInstDTO.setActionType(ActionType.K);
                    return Collections.singletonList(dirtyProdInstDTO);
                }

            }
        }

        return Collections.emptyList();


    }

    /**
     * 参考逻辑：{@link SceneService#getProdRoleModuleVO}
     *
     * @param request
     * @param sceneModule
     * @param dirtyProdInstDTO
     * @return
     */
    protected ProdRoleModuleVO genProdRoleModuleVO(AcceptRequestInDTO request, SceneModule sceneModule, DirtyProdInstDTO dirtyProdInstDTO, DirtyDataWrapper dirtyDataWrapper) {
        ProductModuleVO prodModule = (ProductModuleVO) sceneModule.getParentModuleVO();
        String prodId = dirtyProdInstDTO.getSpecId();
        String roleId = dirtyProdInstDTO.getRoleId();
        String roleName = Optional.ofNullable(OfferObjRelRoleCache.get(roleId)).map(OfferObjRelRole::getRoleName).orElse("");
        String prodInstId = dirtyProdInstDTO.getInstId();

        ProdRoleModuleVO prodRoleModuleVO = new ProdRoleModuleVO();
        prodRoleModuleVO.setProdId(prodId);
        prodRoleModuleVO.setProdRoleId(roleId);

        String deleteFlag = TemplateConsts.TRUE_T;
        if (ActionType.M == dirtyProdInstDTO.getActionType() || ActionType.K == dirtyProdInstDTO.getActionType()) {
            //选老号码 是否可以删除根据老实例判断
            if (dirtyDataWrapper.listDirtyProdInsts(prodId, ActionType.D).size() > 0) {
                String oldProdInstId = dirtyDataWrapper.listDirtyProdInsts(prodId, ActionType.D).get(0).getInstId();
                deleteFlag = prodModule.getProdRole().stream().filter(prodRole -> StringUtils.equals(oldProdInstId, prodRole.getProdInstId())).map(ProdRoleModuleVO::getDeleteFlag).findFirst().orElse(deleteFlag);
            }
        }

        prodRoleModuleVO.setDeleteFlag(deleteFlag);
        prodRoleModuleVO.setFreeFlag(getFreeFlag(deleteFlag, dirtyProdInstDTO.getActionType()));
        prodRoleModuleVO.setProdInstId(prodInstId);
        prodRoleModuleVO.setProdRoleName(roleName);
        prodRoleModuleVO.setModuleName(roleName);
        prodRoleModuleVO.setAdditionalOfferAdd(AdditionalExtProdCache.getInst().isAdditionalOfferAdd(request.getOfferId(), prodId, roleId));

        ProductModuleVO productModuleVO = new ProductModuleVO();
        productModuleVO.setProdId(prodId);
        productModuleVO.setProdRole(Collections.singletonList(prodRoleModuleVO));

        SceneNewOfferSeneVO sceneVO = new SceneNewOfferSeneVO();
        sceneVO.getSceneProductModuleVO().setProduct(Collections.singletonList(productModuleVO));

        AcceptContext moduleExecuteContext = new AcceptContext();
        moduleExecuteContext.setAcceptRequest(request);
        moduleExecuteContext.setSceneVo(sceneVO);

        SceneModule module = SceneModuleCache.get(sceneModule.getKiteModule().getModuleId(), request.getSceneTemplateId());
        module.setParentModuleVO(productModuleVO);
        module.execute(moduleExecuteContext);

        return sceneVO.getSceneProductModuleVO().getProduct().get(0).getProdRole().get(0);
    }

    private String getFreeFlag(String deleteFlag, ActionType actionType) {
        return TemplateConsts.TRUE_T.equals(deleteFlag) && (ActionType.M == actionType || ActionType.K == actionType) ? TemplateConsts.TRUE_T : TemplateConsts.FALSE_F;
    }
}
